"""
LLM异常定义
定义与LLM交互过程中可能出现的各种异常
"""
from typing import Optional, Dict, Any, Type, Tuple, Callable, Pattern
import re


class LLMException(Exception):
	"""LLM适配层基础异常"""
	
	def __init__(self, message: str, provider: Optional[str] = None, model: Optional[str] = None, details: Optional[Dict[str, Any]] = None):
		"""
		初始化LLM异常
		
		Args:
			message: 错误消息
			provider: 提供商名称
			model: 模型名称
			details: 详细错误信息
		"""
		self.provider = provider
		self.model = model
		self.details = details or {}
		
		# 构建完整的错误消息
		full_message = message
		if provider:
			full_message = f"[{provider}] {full_message}"
			if model:
				full_message = f"[{provider}/{model}] {full_message}"
				
		super().__init__(full_message)


class ConfigurationError(LLMException):
	"""配置错误，如无效的配置参数"""
	pass


class ProviderError(LLMException):
	"""提供商相关的错误"""
	pass


class AuthenticationError(ProviderError):
	"""认证错误，如无效的API密钥"""
	pass


class QuotaExceededError(ProviderError):
	"""配额超限错误，如API使用量达到上限"""
	pass


class RateLimitError(ProviderError):
	"""速率限制错误，如请求频率过高"""
	
	def __init__(self, message: str, provider: Optional[str] = None, model: Optional[str] = None, 
				 retry_after: Optional[int] = None, details: Optional[Dict[str, Any]] = None):
		"""
		初始化速率限制错误
		
		Args:
			message: 错误消息
			provider: 提供商名称
			model: 模型名称
			retry_after: 建议重试时间（秒）
			details: 详细错误信息
		"""
		self.retry_after = retry_after
		super().__init__(message, provider, model, details)


class ConnectionError(ProviderError):
	"""网络连接错误"""
	pass


class TimeoutError(ConnectionError):
	"""请求超时错误"""
	pass


class ServerError(ProviderError):
	"""服务器错误，如500错误"""
	pass


class InvalidRequestError(ProviderError):
	"""无效请求错误，如请求参数错误"""
	pass


class ContentFilterError(ProviderError):
	"""内容过滤错误，如输入或输出被内容过滤器拦截"""
	pass


class ModelNotFoundError(ProviderError):
	"""模型不存在错误"""
	pass


class InputTooLongError(ProviderError):
	"""输入过长错误，如超出模型最大token限制"""
	
	def __init__(self, message: str, provider: Optional[str] = None, model: Optional[str] = None, 
				 current_tokens: Optional[int] = None, max_tokens: Optional[int] = None, 
				 details: Optional[Dict[str, Any]] = None):
		"""
		初始化输入过长错误
		
		Args:
			message: 错误消息
			provider: 提供商名称
			model: 模型名称
			current_tokens: 当前输入token数
			max_tokens: 最大允许token数
			details: 详细错误信息
		"""
		self.current_tokens = current_tokens
		self.max_tokens = max_tokens
		
		# 如果有token信息，添加到错误消息中
		if current_tokens is not None and max_tokens is not None:
			message = f"{message} (当前: {current_tokens}, 最大: {max_tokens})"
			
		super().__init__(message, provider, model, details)


class ProviderUnavailableError(ProviderError):
	"""提供商不可用错误，如服务暂时下线"""
	pass


class UnsupportedOperationError(ProviderError):
	"""不支持的操作错误，如某些功能在特定提供商不可用"""
	pass


# 错误映射类型
ErrorPattern = Tuple[Type[ProviderError], str]
ErrorPatternDict = Dict[str, Dict[str, ErrorPattern]]


# 错误模式映射表
# 格式: {provider: {pattern: (error_class, message)}}
ERROR_PATTERNS: ErrorPatternDict = {
	"anthropic": {
		"authentication error": (AuthenticationError, "API密钥认证失败"),
		"rate limit": (RateLimitError, "请求速率超限"),
		"quota exceeded": (QuotaExceededError, "API使用配额已耗尽"),
		"connection": (ConnectionError, "连接到Anthropic API失败"),
		"timeout": (TimeoutError, "请求超时"),
		"server error": (ServerError, "Anthropic服务器错误"),
		"content policy": (ContentFilterError, "内容被Anthropic内容策略过滤"),
		"input too long": (InputTooLongError, "输入文本过长")
	},
	"openai": {
		"authentication": (AuthenticationError, "API密钥认证失败"),
		"rate limit": (RateLimitError, "请求速率超限"),
		"quota": (QuotaExceededError, "API使用配额已耗尽或账单问题"),
		"billing": (QuotaExceededError, "API使用配额已耗尽或账单问题"),
		"connection": (ConnectionError, "连接到OpenAI API失败"),
		"timeout": (TimeoutError, "请求超时"),
		"server error": (ServerError, "OpenAI服务器错误"),
		"500": (ServerError, "OpenAI服务器错误"),
		"content filter": (ContentFilterError, "内容被OpenAI内容过滤器拦截"),
		"moderation": (ContentFilterError, "内容被OpenAI内容过滤器拦截"),
		"maximum context length": (InputTooLongError, "输入超出最大上下文长度"),
		"model not found": (ModelNotFoundError, "模型不存在或不可用")
	},
	"moonshot": {
		"authentication": (AuthenticationError, "API密钥认证失败"),
		"unauthorized": (AuthenticationError, "API密钥认证失败"),
		"rate limit": (RateLimitError, "请求速率超限"),
		"quota": (QuotaExceededError, "API使用配额已耗尽"),
		"connection": (ConnectionError, "连接到Moonshot API失败"),
		"timeout": (TimeoutError, "请求超时"),
		"server error": (ServerError, "Moonshot服务器错误")
	},
	"ollama": {
		"connection": (ConnectionError, "连接到Ollama服务失败"),
		"not found": (ModelNotFoundError, "模型未在Ollama中找到"),
		"timeout": (TimeoutError, "请求超时"),
		"server error": (ServerError, "Ollama服务器错误")
	}
	# 其他提供商的错误映射可以在此添加...
}


# 提供商级别的自定义错误映射函数类型
ErrorMapperFunction = Callable[[str, Exception, Optional[str]], Optional[ProviderError]]


# 提供商错误映射函数注册表
_ERROR_MAPPERS: Dict[str, ErrorMapperFunction] = {}


def register_error_mapper(provider: str, mapper_func: ErrorMapperFunction) -> None:
	"""
	注册提供商特定的错误映射函数
	
	Args:
		provider: 提供商名称
		mapper_func: 错误映射函数，接收原始错误并返回映射后的LLM异常
	"""
	_ERROR_MAPPERS[provider] = mapper_func


def map_provider_error(provider: str, error: Exception, model: Optional[str] = None) -> ProviderError:
	"""
	将提供商特定的错误映射为标准LLM异常
	
	Args:
		provider: 提供商名称
		error: 原始错误
		model: 模型名称
		
	Returns:
		映射后的标准LLM异常
	"""
	# 1. 首先尝试从新模块导入映射函数
	try:
		from ..utils.errors.mapping import map_error_from_provider
		return map_error_from_provider(provider, error, model)
	except ImportError:
		pass
		
	# 2. 然后使用原始实现（向后兼容）
	error_message = str(error).lower()
	error_details = {"original_error": type(error).__name__}
	
	# 尝试使用注册的自定义映射函数
	if provider in _ERROR_MAPPERS:
		mapped_error = _ERROR_MAPPERS[provider](provider, error, model)
		if mapped_error:
			return mapped_error
	
	# 尝试使用错误模式映射表
	if provider in ERROR_PATTERNS:
		patterns = ERROR_PATTERNS[provider]
		for pattern, (error_class, message) in patterns.items():
			if pattern in error_message:
				# 特殊处理模型不存在的错误
				if error_class == ModelNotFoundError and model:
					message = f"模型'{model}'不存在或不可用"
				
				# 提取重试时间（对于速率限制错误）
				if error_class == RateLimitError:
					retry_after = None
					retry_match = re.search(r"retry after (\d+)", error_message)
					if retry_match:
						try:
							retry_after = int(retry_match.group(1))
						except (ValueError, IndexError):
							pass
					
					return RateLimitError(message, provider, model, retry_after, error_details)
				
				return error_class(message, provider, model, error_details)
	
	# 默认映射为通用提供商错误
	return ProviderError(f"提供商错误: {error}", provider, model, error_details)


# 自定义错误映射示例
def _anthropic_error_mapper(provider: str, error: Exception, model: Optional[str]) -> Optional[ProviderError]:
	"""
	Anthropic错误的自定义映射器
	
	Args:
		provider: 提供商名称
		error: 原始错误
		model: 模型名称
		
	Returns:
		映射后的LLM异常，如果无法映射则返回None
	"""
	# 可以根据错误类型或其他信息进行更精细的映射
	error_type = type(error).__name__
	
	# 示例: 特殊处理Anthropic SDK特定的错误类型
	if error_type == "AnthropicError" and hasattr(error, "status_code"):
		status_code = getattr(error, "status_code")
		if status_code == 401:
			return AuthenticationError("API密钥认证失败", provider, model)
		elif status_code == 429:
			return RateLimitError("请求速率超限", provider, model)
		elif status_code == 500:
			return ServerError("Anthropic服务器错误", provider, model)
	
	# 返回None表示使用通用映射机制
	return None


# 注册自定义错误映射器
register_error_mapper("anthropic", _anthropic_error_mapper)
